package com.xw.unification.entity.request;

import com.xw.unification.annotations.RequestRewrite;
import com.xw.unification.interfaces.RepeatableRequestRewriter;
import com.xw.unification.utils.AnnotationDetector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author qiwei
 * @since v1.0.0
 */
public class RepeatableRequestRewriteInterceptor implements HandlerInterceptor, Ordered {

    public static final Logger LOGGER = LoggerFactory.getLogger(RepeatableRequestRewriteInterceptor.class);

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        RepeatableRequestRewriteContext ctx;
        if (handler instanceof HandlerMethod
                && request instanceof CopyOnReadHttpServletRequest
                && supports(request, response, (HandlerMethod) handler, (ctx = new RepeatableRequestRewriteContext()))) {
            return doRewrite((CopyOnReadHttpServletRequest) request, response, (HandlerMethod) handler, ctx);
        } else {
            return true;
        }
    }

    public boolean supports(HttpServletRequest request, HttpServletResponse response,
                            HandlerMethod handlerMethod, RepeatableRequestRewriteContext ctx) {
        RequestRewrite anno = null;
        boolean supports = handlerMethod != null
                && (anno = AnnotationDetector.findAnnotation(handlerMethod, RequestRewrite.class)) != null;
        if (!supports) {
            return false;
        }
        ctx.setAnno(anno);
        return true;
    }

    protected boolean doRewrite(CopyOnReadHttpServletRequest request, HttpServletResponse response,
                                  HandlerMethod handlerMethod, RepeatableRequestRewriteContext ctx) {
        RequestRewrite anno = ctx.getAnno();
        if (anno == null) {
            return false;
        }
        Class<? extends RepeatableRequestRewriter> rewriterClass = anno.rewriter();
        if (rewriterClass == null || !RepeatableRequestRewriter.class.isAssignableFrom(rewriterClass)) {
            return false;
        }
        try {
            RepeatableRequestRewriter rewriter = rewriterClass.newInstance();
            if (rewriter == null) {
                return false;
            }
            return rewriter.rewrite(request, response, handlerMethod, ctx);
        } catch (Exception e) {
            return false;
        }
    }

}
